package com.sfpay.coreplatform.account.service.impl;

import java.util.Random;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sfpay.coreplatform.account.common.AccountResponseCode;
import com.sfpay.coreplatform.account.common.constant.OpenAccConstants;
import com.sfpay.coreplatform.account.common.enums.AccountActive;
import com.sfpay.coreplatform.account.common.enums.AccountState;
import com.sfpay.coreplatform.account.common.enums.AccountType;
import com.sfpay.coreplatform.account.common.enums.FreezeState;
import com.sfpay.coreplatform.account.common.enums.MonitorFlag;
import com.sfpay.coreplatform.account.common.enums.PasswordFlag;
import com.sfpay.coreplatform.account.persistence.dao.IAccountDao;
import com.sfpay.coreplatform.account.persistence.dao.ICommonDao;
import com.sfpay.coreplatform.account.persistence.dao.ISubjectDao;
import com.sfpay.coreplatform.account.service.IAccountMgrService;
import com.sfpay.coreplatform.account.service.exception.AccountServiceException;
import com.sfpay.coreplatform.account.valueobject.dto.OpenAcc;
import com.sfpay.coreplatform.account.valueobject.dto.OpenAccReturn;
import com.sfpay.coreplatform.account.valueobject.tmo.AccountVO;
import com.sfpay.coreplatform.account.valueobject.tmo.Subject;
import com.sfpay.framework.common.util.AssertUtils;
import com.sfpay.framework.common.util.StringUtils;

@Service
public class AccountMgrServiceImpl implements IAccountMgrService {
	
	private static Logger logger = LoggerFactory.getLogger(AccountMgrServiceImpl.class);
	
	@Resource
	private IAccountDao accountDao;
	
	@Resource
	private ICommonDao commonDao;
	
	@Resource
	private ISubjectDao subjectDao;
	
	
	@Override
	@Transactional(rollbackFor=AccountServiceException.class)
	public OpenAccReturn openAccount(OpenAcc openAcc)
			throws AccountServiceException {
		
		
		try {
			logger.debug("openPersonAcc(OpenAcc) - start"); 
			logger.debug("validate openAcc parameter");
			validatorParam(openAcc);

			AccountVO account = new AccountVO();
			OpenAccReturn openAccReturn = new OpenAccReturn();
			
			logger.debug("generate account no");
			Long accountNo = getAccountNo(openAcc.getAccountTypeNo());
			
			String subjectNo = openAcc.getSubjectNo();
			Subject subject = subjectDao.queryBySubjectNO(subjectNo);
			if(subject == null){
				logger.info("The subjectNo " + subjectNo + "is not exist");
				throw new AccountServiceException(AccountResponseCode.ACCOUNT_SUBJECTNO_NOT_EXIST_ERROR, "open account error");
			}
			account.setSubjectDrCr(subject.getSubjectDirection());
			account.setSubjectNo(subjectNo);
			account.setMemberNo(openAcc.getMemberNo());
			account.setAccountType(AccountType.MEMBER_ACC);
			account.setAccountName(subject.getSubjectName());
			account.setAccountNo(accountNo);
			account.setAccountPasswd(openAcc.getAccountPasswd());
			if(openAcc.getAccountActive() == null)
				account.setAccountActive(AccountActive.ACTIVE);
			else
				account.setAccountActive(openAcc.getAccountActive());	
			account.setAccountTypeNo(openAcc.getAccountTypeNo());
			if(openAcc.getFreezeState() == null)
				account.setFreezeState(FreezeState.UNFROZEN);
			else
				account.setFreezeState(openAcc.getFreezeState());
			
			if(openAcc.getAccountState() == null)
				account.setAccountState(AccountState.NORMAL);
			else
				account.setAccountState(openAcc.getAccountState());
			account.setMonitorFlag(MonitorFlag.UN_MONITOR);
			Long defaultLong = Long.valueOf(0);
			account.setCashAmount(defaultLong);
			account.setFreezeAmount(defaultLong);
			
			if(openAcc.getOverdraftAmountLimit()== null)
				account.setOverdraftAmountLimit(0L);
			else
				account.setOverdraftAmountLimit(openAcc.getOverdraftAmountLimit());
			account.setAccountPasswdFlag(PasswordFlag.CHECK);
			accountDao.insert(account);
			logger.debug("set the return value");
			openAccReturn.setAccountNo(accountNo);
			openAccReturn.setMemberNo(openAcc.getMemberNo());
			logger.debug("openPersonAcc(OpenAcc) - end");
			return openAccReturn;
		} catch (AccountServiceException e) {
			throw e;
		}catch (Exception e) {
			logger.error("open account error",e);
			throw new AccountServiceException(AccountResponseCode.ACCOUNT_OPENACC_ERROR,"open account error",e);
		}
		
	}

	@Override
	@Transactional(rollbackFor=AccountServiceException.class)
	public void makeAccountActive(Long accountNo)
			throws AccountServiceException {
		
		logger.info("AccountMgrServiceImpl makeAccountActive start");
		if(accountDao.makeAccountActive(accountNo) < 1){
			logger.error("makeAccountActive error");
			throw new AccountServiceException(AccountResponseCode.ACCOUNT_ACTIVE_ERROR,"makeAccountActive error");
		}
		logger.info("AccountMgrServiceImpl makeAccountActive end");
	}

	@Override
	@Transactional(rollbackFor=AccountServiceException.class)
	public AccountVO makeAccountForbidOut(Long accountNo)
			throws AccountServiceException {
		logger.info("AccountMgrServiceImpl_makeAccountForbidOut start");
		
		AccountVO accountVO = new AccountVO();
		accountVO.setAccountNo(accountNo);
		accountVO.setAccountState(AccountState.OUT_FORBIDEN);
		
		if(accountDao.updateAccountStateByAccountNo(accountVO) < 1){
			logger.error("makeAccountForbidOut error");
			throw new AccountServiceException(AccountResponseCode.ACCOUNT_STATUS_UPDATE_ERROR,"accountStatus update error");
		}
		
		accountVO = accountDao.selectByAccountNo(accountNo);
		
		logger.info("AccountMgrServiceImpl_makeAccountForbidOut success");
		logger.info("AccountMgrServiceImpl_makeAccountForbidOut end");
		return accountVO;
	}

	@Override
	@Transactional(rollbackFor=AccountServiceException.class)
	public AccountVO makeAccountForbidIn(Long accountNo)
			throws AccountServiceException {
		logger.info("AccountMgrServiceImpl_makeAccountForbidIn start");
		
		AccountVO accountVO = new AccountVO();
		accountVO.setAccountNo(accountNo);
		accountVO.setAccountState(AccountState.IN_FORBIDEN);
		
		if(accountDao.updateAccountStateByAccountNo(accountVO) < 1){
			logger.error("makeAccountForbidIn error");
			throw new AccountServiceException(AccountResponseCode.ACCOUNT_STATUS_UPDATE_ERROR,"accountStatus update error");
		}
		
		accountVO = accountDao.selectByAccountNo(accountNo);
		
		logger.info("AccountMgrServiceImpl_makeAccountForbidIn success");
		logger.info("AccountMgrServiceImpl_makeAccountForbidIn end");
		return accountVO;
	}
	
	
	
	/**
	 * 
	 *
	 * 方法说明：参数校验
	 *
	 * @param openAcc
	 *
	 * @author 299015 彭阳
	 */
	private void validatorParam(OpenAcc openAcc) {
		AssertUtils.notNull(openAcc);
		AssertUtils.notNullAndEmpty(openAcc.getMemberNo());
		AssertUtils.notNullAndEmpty(openAcc.getAccountPasswd());
		AssertUtils.notNullAndEmpty(openAcc.getSubjectNo());
		AssertUtils.notNullAndEmpty(openAcc.getAccountTypeNo());
		//AssertUtils.notNullAndEmpty(openAcc.getFreezeState());
		//AssertUtils.notNullAndEmpty(openAcc.getAccountState());
		//AssertUtils.notNullAndEmpty(openAcc.getOverdraftAmountLimit());
	}
	
	/**
	 * 
	 *
	 * 方法说明：生成账户编号
	 *
	 * @param openAcc
	 * @return
	 *
	 * @author 299015 彭阳
	 */
	private Long getAccountNo(int accountTypeNo) {
		int accountHelp = 1000000000;
		int seqLenth = 9;
		String seq = commonDao.selectSeqValue(OpenAccConstants.SEQ_ACCOUNT_NO);
		seq = String.valueOf(accountHelp - Integer.parseInt(seq)%accountHelp);
		logger.debug("Fill 0");
		while(seq.length() < seqLenth){
			seq = "0" + seq;
		}
		logger.debug("sequence:"+seq);
		String firstTwoNo = OpenAccConstants.FIRST_TWO_NO;//2位固定位
		String ranNo = String.valueOf(new Random().nextInt(10));//随机位
		logger.debug("generate random no:"+ranNo) ;
		String seriaNoTmp = firstTwoNo + ranNo + seq;
		logger.debug("sequence befer transfer:"+seriaNoTmp) ;
		char charAt11 = seriaNoTmp.charAt(11);
		char charAt4 = seriaNoTmp.charAt(4);
		char charAt10 = seriaNoTmp.charAt(10);
		char charAt7 = seriaNoTmp.charAt(7);
		char charAt9 = seriaNoTmp.charAt(9);
		char charAt2 = seriaNoTmp.charAt(2);
		char charAt5 = seriaNoTmp.charAt(5);
		char charAt0 = seriaNoTmp.charAt(0);
		char [] charTmp = seriaNoTmp.toCharArray();
		charTmp[11] = charAt4;
		charTmp[4] = charAt11;
		charTmp[10] = charAt7;
		charTmp[7] = charAt10;
		charTmp[9] = charAt2;
		charTmp[2] = charAt9;
		charTmp[5] = charAt0;
		charTmp[0] = charAt5;
		String seriaNo = String.copyValueOf(charTmp);//序列号

		logger.debug("The sequencde is :"+seriaNo) ;
		String strTemp = String.valueOf(accountTypeNo) + seriaNo;
		int sum = 0;
		for (int i = 0; i < strTemp.length(); i++) {
			sum = sum + Integer.parseInt(String.valueOf(strTemp.charAt(i)));
		}
		String checkNo = String.valueOf(sum%10);//校验位
		Long accountNo = Long.valueOf(accountTypeNo + seriaNo + checkNo) ;//账户编号
		logger.debug("The account is:"+accountNo) ;
		return accountNo;
	}

	@Override
	@Transactional(rollbackFor=AccountServiceException.class)
	public AccountVO makeAccountNormal(Long accountNo) throws AccountServiceException {
		logger.info("AccountMgrServiceImpl_makeAccountNormal start");
		
		AccountVO accountVO = new AccountVO();
		accountVO.setAccountNo(accountNo);
		accountVO.setAccountState(AccountState.NORMAL);
		
		if(accountDao.updateAccountStateByAccountNo(accountVO) < 1){
			logger.error("makeAccountNormal error");
			throw new AccountServiceException(AccountResponseCode.ACCOUNT_STATUS_UPDATE_ERROR,"accountStatus update error");
		}
		
		accountVO = accountDao.selectByAccountNo(accountNo);
		
		logger.info("AccountMgrServiceImpl_makeAccountNormal success");
		logger.info("AccountMgrServiceImpl_makeAccountNormal end");
		return accountVO;
	}

	@Override
	@Transactional(rollbackFor=AccountServiceException.class)
	public AccountVO makeAccountCancel(Long accountNo)
			throws AccountServiceException {
		
		logger.info("AccountMgrServiceImpl_makeAccountCanceled start");
		AccountVO accountVO = new AccountVO();
		accountVO.setAccountNo(accountNo);
		accountVO.setAccountState(AccountState.CANCEL);
		
		if(accountDao.updateAccountStateByAccountNo(accountVO) < 1){
			logger.error("makeAccountCanceled error");
			throw new AccountServiceException(AccountResponseCode.ACCOUNT_STATUS_UPDATE_ERROR,"accountStatus update error");
		}
		
		accountVO = accountDao.selectByAccountNo(accountNo);
		
		logger.info("AccountMgrServiceImpl_makeAccountCancel success");
		logger.info("AccountMgrServiceImpl_makeAccountCancel end");
		return accountVO;
	}

}
